package org.janusproject.demos.acl.cnp.role;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.janusproject.acl.Performative;
import org.janusproject.acl.protocol.ProtocolResult;
import org.janusproject.acl.protocol.cnp.FipaContractNetProtocol;
import org.janusproject.kernel.crio.core.Role;
import org.janusproject.kernel.status.Status;
import org.janusproject.kernel.status.StatusFactory;

public class ContractNetAnswerer extends Role {

	private State state;
	private FipaContractNetProtocol contractNetProtocol;
	private ProtocolResult callForProposal;
	
	@Override
	public Status live() {
		state = HandleRequest();
		return StatusFactory.ok(this);
	}
	
	public Status activate(Object... parameters) {
		
		for (Object parameter : parameters) {
			if (parameter instanceof FipaContractNetProtocol) {
				contractNetProtocol = (FipaContractNetProtocol) parameter;
				state = State.WAITING_CALL_FOR_PROPOSAL;
				return StatusFactory.ok(this);
			}
		}
		
		return StatusFactory.cancel(this);
	}
	
	private State HandleRequest() {
		
		if( contractNetProtocol.hasFailed() ){
			leaveMe();
		}
		
		switch (this.state) 
		{
			case WAITING_CALL_FOR_PROPOSAL: 
			{
				callForProposal = contractNetProtocol.getCallForProposal();
				
				if( callForProposal != null ){
					log("cfp received");
					return State.SENDING_PROPOSAL;
					
					//contractNetProtocol.notUnderstood("?");
					//return State.DONE;
				}
				
				return State.WAITING_CALL_FOR_PROPOSAL;
			}
			case SENDING_PROPOSAL:
			{
				if( callForProposal.getContent().toString().equalsIgnoreCase("description of the task") ){
					contractNetProtocol.propose("120");
					log("proposal sent");
					return State.WAITING_PROPOSAL_ANSWER;
				}
				else{
					contractNetProtocol.refuse("not interested in");
					log("refusal sent");
					return State.DONE;
				}
			}
			case WAITING_PROPOSAL_ANSWER:
			{
				ProtocolResult result = contractNetProtocol.getAnswerToCallForProposal();
				
				if (result != null) {
					
					if (result.getPerformative().compareTo(Performative.ACCEPT_PROPOSAL) == 0) {
						log("accept-proposal received");
						return State.SENDING_RESULT;
					} 
					else if (result.getPerformative().compareTo(Performative.REJECT_PROPOSAL) == 0) {
						log("reject-proposal received");
						return State.REJECTED;
					} 
				}

				return State.WAITING_PROPOSAL_ANSWER;
			}
			case SENDING_RESULT:
			{
				//contractNetProtocol.informDone("task completed");
				contractNetProtocol.informResult("task completed");
				//contractNetProtocol.failure("task failed");
				
				log("result sent");
				
				return State.DONE;
			}
			case REJECTED:
			{
				log("proposal has been rejected => done");
				leaveMe();
			}
			case DONE:
			{
				log("done");
				leaveMe();
			}
		default:
			return this.state;
		}
	}
	
	private void log(String str){
		Logger.getAnonymousLogger().log(Level.INFO, "[" + getPlayer() + "] : "+str);
	}
	
	public enum State{
		NOT_STARTED,
		WAITING_CALL_FOR_PROPOSAL,
		SENDING_PROPOSAL,
		WAITING_PROPOSAL_ANSWER,
		SENDING_RESULT,
		CANCELING,
		CANCELED,
		REJECTED,
		DONE;
	}
}
